package com.unstoppable.submitbuttonview;

import com.unstoppable.submitbuttonview.utils.LogUtil;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.render.Path;
import ohos.agp.render.PathMeasure;
import ohos.agp.utils.Color;
import ohos.agp.utils.Rect;
import ohos.agp.utils.RectFloat;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;

/**
 * Created by Unstoppable on 2016/12/31.
 */

public class SubmitButton extends Component implements Component.DrawTask{
    private static final String TAG = "SubmitButton-->";
    private static final String SUBMIT_BUTTON_TEXT = "buttonText";
    private static final String SUBMIT_BUTTON_COLOR = "buttonColor";
    private static final String SUBMIT_SUCCEED_COLOR = "succeedColor";
    private static final String SUBMIT_FAILED_COLOR = "failedColor";
    private static final String SUBMIT_BUTTON_SIZE = "buttonTextSize";
    private static final String SUBMIT_PROGRESS_STYLE = "progressStyle";

    private static final int STATE_NONE = 0;
    private static final int STATE_SUBMIT = 1;
    private static final int STATE_LOADING = 2;
    private static final int STATE_RESULT = 3;

    //view状态
    private int viewState = STATE_NONE;

    //View宽高
    private int mWidth;
    private int mHeight;

    private int MAX_WIDTH;
    private int MAX_HEIGHT;

    //画布坐标原点
    private int x, y;

    private String buttonText = "test";
    private Color buttonColor = new Color(Color.getIntColor("#DAA520"));
    private Color succeedColor = new Color(Color.getIntColor("#00FA9A"));
    private Color failedColor = new Color(Color.getIntColor("#DC143C"));
    private int textSize = 18;
    private String pgStyle = "loading";

    private boolean isMeasure = true;

    //文本宽高
    private int textWidth;
    private int textHeight;

    private Paint bgPaint, loadingPaint, resultPaint, textPaint;

    private Path buttonPath;
    private Path loadPath;
    private Path dst;
    private PathMeasure pathMeasure;
    private Path resultPath;

    private float loadValue;

    private AnimatorValue submitAnim, loadingAnim, resultAnim;

    private boolean isDoResult;
    private boolean isSucceed;

    private static final int STYLE_LOADING = 0;
    private static final int STYLE_PROGRESS = 1;

    //view加载等待模式
    private int progressStyle = STYLE_LOADING;
    private float currentProgress;

    private OnResultEndListener listener;


    public SubmitButton(Context context) {
        this(context, null);
    }

    public SubmitButton(Context context, AttrSet attrs) {
        this(context, attrs, 0);
    }

    public SubmitButton(Context context, AttrSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        buttonText = attrs.getAttr(SUBMIT_BUTTON_TEXT).isPresent() ? attrs.getAttr(SUBMIT_BUTTON_TEXT).get().getStringValue() : buttonText;
        buttonColor = attrs.getAttr(SUBMIT_BUTTON_COLOR).isPresent() ? attrs.getAttr(SUBMIT_BUTTON_COLOR).get().getColorValue() : buttonColor;
        succeedColor = attrs.getAttr(SUBMIT_SUCCEED_COLOR).isPresent() ? attrs.getAttr(SUBMIT_SUCCEED_COLOR).get().getColorValue() : succeedColor;
        failedColor = attrs.getAttr(SUBMIT_FAILED_COLOR).isPresent() ? attrs.getAttr(SUBMIT_FAILED_COLOR).get().getColorValue() : failedColor;
        textSize = attrs.getAttr(SUBMIT_BUTTON_SIZE).isPresent() ? attrs.getAttr(SUBMIT_BUTTON_SIZE).get().getIntegerValue() : textSize;
        pgStyle = attrs.getAttr(SUBMIT_PROGRESS_STYLE).isPresent() ? attrs.getAttr(SUBMIT_PROGRESS_STYLE).get().getStringValue() : pgStyle;
        switch (pgStyle) {
            case "loading":
                progressStyle = STYLE_LOADING;
                break;
            case "progress":
                progressStyle = STYLE_PROGRESS;
                break;
        }
        init();
    }

    /**
     * 初始化Paint、Path
     */
    private void init() {
        bgPaint = new Paint();
        bgPaint.setColor(buttonColor);
        bgPaint.setStyle(Paint.Style.STROKE_STYLE);
        bgPaint.setStrokeWidth(5);
        bgPaint.setAntiAlias(true);

        loadingPaint = new Paint();
        loadingPaint.setColor(buttonColor);
        loadingPaint.setStyle(Paint.Style.STROKE_STYLE);
        loadingPaint.setStrokeWidth(5);
        loadingPaint.setAntiAlias(true);

        resultPaint = new Paint();
        resultPaint.setColor(Color.WHITE);
        resultPaint.setStyle(Paint.Style.STROKE_STYLE);
        resultPaint.setStrokeWidth(9);
        resultPaint.setStrokeCap(Paint.StrokeCap.ROUND_CAP);
        resultPaint.setAntiAlias(true);

        textPaint = new Paint();
        textPaint.setColor(buttonColor);
        textPaint.setStrokeWidth(textSize / 6);
        textPaint.setTextSize(textSize);
        textPaint.setAntiAlias(true);

        resultAnim = new AnimatorValue();
        submitAnim = new AnimatorValue();
        loadingAnim = new AnimatorValue();

        textWidth = getTextWidth(textPaint, buttonText);
        textHeight = getTextHeight(textPaint, buttonText);

        buttonPath = new Path();
        loadPath = new Path();
        resultPath = new Path();
        dst = new Path();

        addDrawTask(this);
//        setTouchEventListener(this);

        setBindStateChangedListener(new BindStateChangedListener() {
            @Override
            public void onComponentBoundToWindow(Component component) {

            }

            @Override
            public void onComponentUnboundFromWindow(Component component) {
                if (submitAnim != null) {
                    submitAnim.cancel();
                }
                if (loadingAnim != null) {
                    loadingAnim.cancel();
                }
                if (resultAnim != null) {
                    resultAnim.cancel();
                }
            }
        });
    }

    /**
     * onMeasure内方法
     * 风格化
     *
     * @param component
     */
    private void measure(Component component) {
        int widthMode = MeasureSpec.getMode(component.getWidth());
        int widthSize = MeasureSpec.getSize(component.getWidth());
        int heightMode = MeasureSpec.getMode(component.getHeight());
        int heightSize = MeasureSpec.getSize(component.getHeight());
        LogUtil.error(TAG, "widthMode====" + widthMode + "-------" + "heightMode=====" + heightMode);

//        if (widthMode == MeasureSpec.AT_MOST) {
//            widthSize = textWidth + 100;
//        }
//
//        if (heightMode == MeasureSpec.AT_MOST) {
//            heightSize = (int) (textHeight * 2.5);
//        }

        if (heightSize > widthSize) {
            heightSize = (int) (widthSize * 0.25);
        }

        mWidth = widthSize - 10;
        mHeight = heightSize - 10;
        x = (int) (widthSize * 0.5);
        y = (int) (heightSize * 0.5);
        MAX_WIDTH = mWidth;
        MAX_HEIGHT = mHeight;
        LogUtil.error(TAG, "MAX_WIDTH===" + mWidth + "----" + "MAX_HEIGHT===" + mHeight);
//        setMeasuredDimension(widthSize, heightSize);
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        if (isMeasure) {
            isMeasure = false;
            measure(component);
        }


        canvas.translate(x, y);
        drawButton(canvas);
        if (viewState == STATE_NONE || viewState == STATE_SUBMIT && mWidth > textWidth) {
            drawButtonText(canvas);
        }

        if (viewState == STATE_LOADING) {
            drawLoading(canvas);
        }

        if (viewState == STATE_RESULT) {
            drawResult(canvas, isSucceed);
        }
    }


    /**
     * 绘制初始状态Button
     *
     * @param canvas 画布
     */
    private void drawButton(Canvas canvas) {
        buttonPath.reset();
        buttonPath.arcTo(new RectFloat(-mWidth / 2, -mHeight / 2, -mWidth / 2 + mHeight, mHeight / 2), 90, 180);
        buttonPath.lineTo(mWidth / 2 - mHeight / 2, -mHeight / 2);
        buttonPath.arcTo(new RectFloat(mWidth / 2 - mHeight, -mHeight / 2, mWidth / 2, mHeight / 2), 270, 180);
        buttonPath.lineTo(-mWidth / 2 + mHeight / 2, mHeight / 2);
        canvas.drawPath(buttonPath, bgPaint);
    }

    /**
     * 绘制加载状态Button
     *
     * @param canvas 画布
     */
    private void drawLoading(Canvas canvas) {
        LogUtil.error(TAG, "绘制加载状态Button----");
        //TODO 截取path路径代码无效，问题已经上报正在处理
//        dst.reset();
//        loadPath.addArc(new RectFloat(-MAX_HEIGHT / 2, -MAX_HEIGHT / 2, MAX_HEIGHT / 2, MAX_HEIGHT / 2), 270, 359.999f);
//        pathMeasure = new PathMeasure(loadPath, true);
//        pathMeasure.setPath(loadPath,true);
//        float startD = 0f, stopD;
//        if (progressStyle == STYLE_LOADING) {
//            startD = pathMeasure.getLength() * loadValue;
//            stopD = startD + pathMeasure.getLength() / 2 * loadValue;
//        LogUtil.error("yuxh ","pathMeasure.getLength() = "+pathMeasure.getLength()+" /// "+"startD= "+startD+"   ///   "+"stopD= "+stopD);
//        } else {
//            stopD = pathMeasure.getLength() * currentProgress;
//        }
//        pathMeasure.getSegment(startD, stopD, dst, true);
//        canvas.drawPath(dst, loadingPaint);


        //TODO 临时处理方案
        loadPath.reset();
        loadPath.addArc(new RectFloat(-MAX_HEIGHT / 2, -MAX_HEIGHT / 2, MAX_HEIGHT / 2, MAX_HEIGHT / 2), 270, 359.999f * loadValue);

        canvas.drawPath(loadPath, loadingPaint);
    }

    /**
     * 绘制结果状态Button
     *
     * @param canvas 画布
     * @param isSucceed string
     */
    private void drawResult(Canvas canvas, boolean isSucceed) {
        if (isSucceed) {
            resultPath.moveTo(-mHeight / 6, 0);
            resultPath.lineTo(0, (float) (-mHeight / 6 + (1 + Math.sqrt(5)) * mHeight / 12));
            resultPath.lineTo(mHeight / 6, -mHeight / 6);
        } else {
            resultPath.moveTo(-mHeight / 6, mHeight / 6);
            resultPath.lineTo(mHeight / 6, -mHeight / 6);
            resultPath.moveTo(-mHeight / 6, -mHeight / 6);
            resultPath.lineTo(mHeight / 6, mHeight / 6);
        }
        canvas.drawPath(resultPath, resultPaint);
    }

    /**
     * 绘制Button文本
     *
     * @param canvas 画布
     */
    private void drawButtonText(Canvas canvas) {
        textPaint.setAlpha(((mWidth - textWidth) * 255) / (MAX_WIDTH - textWidth));
        canvas.drawText(textPaint, buttonText, -textWidth / 2, getTextBaseLineOffset());
    }

    /**
     * 第一步缩短动画
     * 开始提交动画
     */
    private void startSubmitAnim() {
        LogUtil.error(TAG, "开始动画");
        viewState = STATE_SUBMIT;


        submitAnim.setValueUpdateListener(new AnimatorValue.ValueUpdateListener() {
            @Override
            public void onUpdate(AnimatorValue animatorValue, float v) {
                //MAX_WIDTH(390) --->MAX_HEIGHT(90),两点之间
                mWidth = (int) (MAX_WIDTH - (MAX_WIDTH - MAX_HEIGHT) * v);
                invalidate();
                if (v == 1.0) {
                    bgPaint.setColor(new Color(Color.getIntColor("#DDDDDD")));
                }
            }
        });

        submitAnim.setStateChangedListener(new Animator.StateChangedListener() {
            @Override
            public void onStart(Animator animator) {
                LogUtil.error(TAG, "onStart");
            }

            @Override
            public void onStop(Animator animator) {

            }

            @Override
            public void onCancel(Animator animator) {
                LogUtil.error(TAG, "onCancel");
            }

            @Override
            public void onEnd(Animator animator) {
                LogUtil.error(TAG, "onEnd");
                if (isDoResult && progressStyle == STYLE_LOADING) {
                    LogUtil.error(TAG, "onEnd----->startResultAnim");
                    startResultAnim();
                } else {
                    LogUtil.error(TAG, "onEnd----->startLoadingAnim");
                    startLoadingAnim();
                }
                submitAnim.stop();
            }

            @Override
            public void onPause(Animator animator) {

            }

            @Override
            public void onResume(Animator animator) {

            }
        });

        submitAnim.setDuration(800);
        submitAnim.setCurveType(Animator.CurveType.ACCELERATE);
        submitAnim.start();
    }

    /**
     * 转圈圈动画
     * 开始加载动画
     */
    private void startLoadingAnim() {
        viewState = STATE_LOADING;
        loadingAnim.setValueUpdateListener(new AnimatorValue.ValueUpdateListener() {
            @Override
            public void onUpdate(AnimatorValue animatorValue, float v) {
                loadValue = v;
                LogUtil.error(TAG, "开始加载动画----->" + v);
                invalidate();
            }
        });
        loadingAnim.setStateChangedListener(new Animator.StateChangedListener() {
            @Override
            public void onStart(Animator animator) {

            }

            @Override
            public void onStop(Animator animator) {

            }

            @Override
            public void onCancel(Animator animator) {

            }

            @Override
            public void onEnd(Animator animator) {
                LogUtil.error(TAG, "onEnd--->重复动画");
                //重复动画在这里设置
//                if (viewState == STATE_LOADING && progressStyle == STYLE_LOADING) {
//                    LogUtil.error(TAG, "onEnd--->开始重复动画");
//
//                }
                loadingAnim.start();
            }

            @Override
            public void onPause(Animator animator) {

            }

            @Override
            public void onResume(Animator animator) {

            }
        });
        loadingAnim.setDuration(1500);
        //重复加载动画方法
//        loadingAnim.setRepeatCount(ValueAnimator.INFINITE);
        loadingAnim.start();
    }

    /**
     * 成功或失败动画
     * 开始结果动画
     */
    private void startResultAnim() {
        viewState = STATE_RESULT;
        if (loadingAnim != null) {
            loadingAnim.cancel();
        }
        resultAnim.setValueUpdateListener(new AnimatorValue.ValueUpdateListener() {
            @Override
            public void onUpdate(AnimatorValue animatorValue, float v) {
                //MAX_HEIGHT(90)------->MAX_WIDTH(390) --->两点之间
                if (isSucceed) {
                    bgPaint.setColor(succeedColor);
                } else {
                    bgPaint.setColor(failedColor);
                }
                mWidth = (int) (MAX_HEIGHT - (MAX_HEIGHT - MAX_WIDTH) * v);
                resultPaint.setAlpha(((mWidth - mHeight) * 255) / (MAX_WIDTH - MAX_HEIGHT));

                if (v == 1.0) {
                    bgPaint.setStyle(Paint.Style.FILLANDSTROKE_STYLE);
                }

                invalidate();
            }
        });
        resultAnim.setStateChangedListener(new Animator.StateChangedListener() {
            @Override
            public void onStart(Animator animator) {

            }

            @Override
            public void onStop(Animator animator) {

            }

            @Override
            public void onCancel(Animator animator) {

            }

            @Override
            public void onEnd(Animator animator) {
                if (listener == null) {
                    return;
                }

                new EventHandler(EventRunner.create()).postTask(new Runnable() {
                    @Override
                    public void run() {
                        listener.onResultEnd();
                    }
                }, 500);
            }

            @Override
            public void onPause(Animator animator) {

            }

            @Override
            public void onResume(Animator animator) {

            }
        });
        resultAnim.setDuration(800);
        submitAnim.setCurveType(Animator.CurveType.ACCELERATE);
        resultAnim.start();
    }


    /**
     * 设置submit结果
     *
     * @param isSucceed 是否成功
     */
    public void doResult(boolean isSucceed) {
        isDoResult = true;
        this.isSucceed = isSucceed;
        startSubmitAnim();
    }

    /**
     * 转圈圈结果判定
     * @param isSucceed
     */
    public void loadingDoResult(boolean isSucceed){
        this.isSucceed = isSucceed;
        startResultAnim();
    }

    /**
     * 恢复初始化Button状态
     */
    public void reset() {
        if (submitAnim != null) {
            submitAnim.cancel();
        }
        if (loadingAnim != null) {
            loadingAnim.cancel();
        }
        if (resultAnim != null) {
            resultAnim.cancel();
        }
        viewState = STATE_NONE;
        mWidth = MAX_WIDTH;
        mHeight = MAX_HEIGHT;
        isSucceed = false;
        isDoResult = false;
        currentProgress = 0;
        init();
        invalidate();
    }

    /**
     * 设置进度
     *
     * @param progress 进度值 (0-100)
     */
    public void setProgress(int progress) {
        if (progress < 0 || progress > 100) {
            return;
        }
        currentProgress = (float) (progress * 0.01);
        if (progressStyle == STYLE_PROGRESS && viewState == STATE_LOADING) {
            invalidate();
        }
    }


    /**
     * 设置动画结束回调接口
     *
     * @param listener
     */
    public void setOnResultEndListener(OnResultEndListener listener) {
        this.listener = listener;
    }


    /**
     * 结果动画结束回调接口
     */
    public interface OnResultEndListener {
        void onResultEnd();
    }

    /**
     * sp to dp
     *
     * @param sp
     * @return dp
     */
    private int sp2px(float sp) {
        final float fontScale = getContext().getResourceManager().getDeviceCapability().screenDensity / 160;
        return (int) (sp * fontScale + 0.5f);
    }

    /**
     * 计算水平居中的baseline
     *
     * @return ohos
     */
    private float getTextBaseLineOffset() {
        Paint.FontMetrics fm = textPaint.getFontMetrics();
        return -(fm.bottom + fm.top) / 2;
    }

    /**
     * 获取Text高度
     *
     * @param paint string
     * @param str   文本内容
     * @return ohos
     */
    private int getTextHeight(Paint paint, String str) {
        Rect textBounds = paint.getTextBounds(str);
        return textBounds.getHeight();
    }

    /**
     * 获取Text宽度
     *
     * @param paint string
     * @param str   文本内容
     * @return ohos
     */
    private int getTextWidth(Paint paint, String str) {
        int mRet = 0;
        if (str != null && str.length() > 0) {
            int len = str.length();
            float[] widths = new float[len];
//            paint.getTextWidths(str, widths);
            paint.getAdvanceWidths(str, widths);
            for (int j = 0; j < len; j++) {
                mRet += (int) Math.ceil(widths[j]);
            }
        }
        return mRet;
    }
}